home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Collection of Tools & Utilities
/
Collection of Tools and Utilities.iso
/
asmutil
/
afloat.zip
/
F_SUB.ASM
< prev
next >
Wrap
Assembly Source File
|
1988-03-15
|
4KB
|
183 lines
PAGE ,132
;----------------------------------------------------------
; F_SUB -- version for use with assembly-language programs
;
; Copyright Bob Kline 1988
;
; Purpose:
; Subtract one single-precision floating-point number
; from another.
;
; Input:
; Minuend in DX:AX and subtrahend in CX:BX as 4-byte reals
; to be subtracted in IEEE format.
;
; Output:
; Result (IEEE) is single-precision real in DX:AX.
;
; Other registers affected:
; BX, CX, DI, SI, BP
;
; Procedures:
; F_ADD
;
; Comments:
; Sets external variable _errno to ERANGE if over-
; flow occurs. If a calling routine will be testing
; _errno, it must first reset the variable to zero
; to be sure that an error code is not left over
; from some previous call. If the signs of the two
; operands differ the sign of the subtrahend is
; flipped and F_ADD is called.
;----------------------------------------------------------
.MODEL SMALL
PUBLIC F_SUB
EXTRN _errno:WORD,F_ADD:PROC
ERANGE EQU 34
.CODE
F_SUB PROC
; check the sign
MOV SI,DX
XOR SI,CX
JNS SAME_SIGNS
; signs are different -- change sign of subtrahend
; and use F_ADD
XOR CX,8000h
CALL F_ADD
RET
; sign same for both -- save it
SAME_SIGNS:
MOV SI,DX
AND SI,8000h
PUSH SI
; unpack exponent and remove bias
MOV DI,DX
MOV SI,CX
SHL DX,1
SHL CX,1
XCHG DH,DL
XCHG CH,CL
XOR DH,DH
XOR CH,CH
SUB DX,127
SUB CX,127
XCHG DI,DX
XCHG SI,CX
; unpack the mantissas & slide over to the left
; one position so we'll have elbowroom to catch
; any lost low bit for rounding
AND DX,7Fh
AND CX,7Fh
OR DX,80h
OR CX,80h
SHL AX,1
RCL DX,1
SHL BX,1
RCL CX,1
; use BP instead of CX for high word of subtrahend so
; we can use CX for shift counting
MOV BP,CX
; check to see which number is bigger
CMP DI,SI
JG SUBTRAHEND_LOWER
JL MINUEND_LOWER
CMP DX,BP
JG SUBTRAHEND_LOWER
JL MINUEND_LOWER
CMP AX,BX
JG SUBTRAHEND_LOWER
JL MINUEND_LOWER
; operands equal -- return 0.0
POP SI
XOR AX,AX
XOR DX,DX
RET
; the minuend is lower than the subtrahend -- swap
; operands & flip the sign
MINUEND_LOWER:
XCHG DX,BP
XCHG AX,BX
XCHG DI,SI
POP CX
XOR CX,8000h
PUSH CX
; now the subtrahend is lower than the minuend --
; if the exponents are different adjust subtrahend
; so that they're the same
SUBTRAHEND_LOWER:
MOV CX,DI
SUB CX,SI
JZ DO_SUB
; if the second number is so much smaller than than first
; that subtracting it in will not make any difference, don't bother
CMP CX,24
JA SHIFTBACK
; here's the shift-right loop for the subtrahend
LOOP1: SHR BP,1
RCR BX,1
LOOP LOOP1
; do the subtraction
DO_SUB: SUB AX,BX
SBB DX,BP
; see if we need to shift back to the right and round
SHIFTBACK:
TEST DX,100h
JZ SHIFTUP
ADD AX,1
ADC DX,0
SHR DX,1
RCR AX,1
JMP SHORT REPACK
; normalize mantissa if necessary
LOOP2: SHL AX,1
RCL DX,1
SHIFTUP:
DEC DI
TEST DX,80h
JZ LOOP2
; make top bit of mantissa invisible -- it's understood
REPACK: AND DX,7Fh
; restore exponent bias
MOV BX,DI
ADD BX,127
; test for valid exponent and re-pack
OR BH,BH
JZ EXP_OK
MOV _errno,ERANGE
XOR BH,BH
EXP_OK: XCHG BH,BL
SHR BX,1
OR DX,BX
; get sign back and we're done
POP CX
OR DX,CX
RET
F_SUB ENDP
END